package com.ruoyi.common.utils;

import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.web.multipart.MultipartFile;

import javax.net.ssl.*;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * http请求工具类
 *
 * @author ruoyi
 */
@Slf4j
public class HttpUtil {

    private static OkHttpClient okHttpClient;

    private static synchronized OkHttpClient getInstance() {
        if (okHttpClient == null) {
            okHttpClient = new OkHttpClient.Builder()
                    .connectTimeout(1000, TimeUnit.SECONDS)
                    .followRedirects(false)
                    .readTimeout(1000, TimeUnit.SECONDS)
                    .sslSocketFactory(createSSLSocketFactory(), new TrustAllCerts())
                    .hostnameVerifier(new TrustAllHostnameVerifier())
                    .retryOnConnectionFailure(true)
                    .build();
            okHttpClient.dispatcher().setMaxRequests(100000000);
            okHttpClient.dispatcher().setMaxRequestsPerHost(100000000);
        }
        return okHttpClient;
    }

    private HttpUtil() {
    }

    public static Response get(String url, Map<String, Object> params, Map<String, String> headers) throws IOException {
        if (params != null && !params.isEmpty()) {
            url = url + "?" + buildQuery(params, true);
        }
        Request.Builder requestBuilder = new Request.Builder()
                .url(url);
        if (headers != null) {
            requestBuilder.headers(Headers.of(headers));
        }

        Response response = null;
        try {
            response = getInstance().newCall(requestBuilder.build()).execute();
        } finally {
            if (response == null) {
                log.info("http get: url={}, requestHeaders={}", url, headers);
            } else {
//                log.info("http get: url={}, requestHeaders={}, responseCode={}, responseHeaders={}",
//                        url, headers, response.code(), response.headers().toMultimap());
            }
        }
        return response;
    }

    public static Response post(String url, Map<String, Object> params, String body, Map<String, String> headers) throws Exception {
        if (params != null && !params.isEmpty()) {
            url = url + "?" + buildQuery(params, true);
        }
        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
        RequestBody requestBody = RequestBody.create(mediaType, body);
        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .post(requestBody);
        if (headers != null) {
            requestBuilder.headers(Headers.of(headers));
        }

        Response response = null;
        try {
            response = getInstance().newCall(requestBuilder.build()).execute();
        } finally {
            if (response == null) {
                log.info("http post: url={}, requestHeaders={}, requestBody={}", url, headers, body);
            } else {
//                log.info("http post: url={}, requestHeaders={}, requestBody={}, responseCode={}, responseHeaders={}",
//                        url, headers, body, response.code(), response.headers().toMultimap());
            }
        }
        return response;
    }


    public static Response put(String url, Map<String, Object> params, String body, Map<String, String> headers) throws Exception {
        if (params != null && !params.isEmpty()) {
            url = url + "?" + buildQuery(params, true);
        }
        MediaType mediaType = MediaType.parse("application/json; charset=utf-8");
        RequestBody requestBody = RequestBody.create(mediaType, body);
        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .put(requestBody);  // 修改这里：将 .post(requestBody) 改为 .put(requestBody)
        if (headers != null) {
            requestBuilder.headers(Headers.of(headers));
        }

        Response response = null;
        try {
            response = getInstance().newCall(requestBuilder.build()).execute();
        } finally {
            if (response == null) {
                log.info("http put: url={}, requestHeaders={}, requestBody={}", url, headers, body);  // 可选：修改日志标识符为 put
            } else {
//                log.info("http put: url={}, requestHeaders={}, requestBody={}, responseCode={}, responseHeaders={}",
//                        url, headers, body, response.code(), response.headers().toMultimap());
            }
        }
        return response;
    }


    /**
     * 文件上传
     *
     * @param url
     * @param params
     * @param file
     * @param headers
     * @return
     * @throws IOException
     */

    public static Response post(String url, MultipartFile file, Map<String, Object> params, String body, Map<String, String> headers) throws IOException {
        if (params != null && !params.isEmpty()) {
            url = url + "?" + buildQuery(params, true);
        }

        MultipartBody.Builder requestBodyBuilder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM);

        if (file != null && !file.isEmpty()) {
            MediaType mediaType = MediaType.parse(file.getContentType());
            requestBodyBuilder.addFormDataPart("file", file.getOriginalFilename(),
                    RequestBody.create(file.getBytes(), mediaType));
        }

        if (params != null) {
            for (Map.Entry<String, Object> entry : params.entrySet()) {
                requestBodyBuilder.addFormDataPart(entry.getKey(), String.valueOf( entry.getValue()));
            }
        }

        Request.Builder requestBuilder = new Request.Builder()
                .url(url)
                .post(requestBodyBuilder.build());

        if (headers != null) {
            requestBuilder.headers(Headers.of(headers));
        }
        Response response = null;
        try {
            response = getInstance().newCall(requestBuilder.build()).execute();
        } finally {
            if (response == null) {
                log.info("http post: url={}, requestHeaders={}, requestBody={}", url, headers, body);
            } else {
//                log.info("http post: url={}, requestHeaders={}, requestBody={}, responseCode={}, responseHeaders={}",
//                        url, headers, body, response.code(), response.headers().toMultimap());
            }
        }
        return response;
    }


    private static String buildQuery(Map<String, Object> params, boolean encode) throws UnsupportedEncodingException {
        StringBuilder query = new StringBuilder();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            if (encode) {
                query.append(URLEncoder.encode(entry.getKey(), "utf-8"))
                        .append("=")
                        .append(URLEncoder.encode(String.valueOf(entry.getValue()) , "utf-8"))
                        .append("&");
            } else {
                query.append(entry.getKey())
                        .append("=")
                        .append(entry.getValue())
                        .append("&");
            }
        }
        query.deleteCharAt(query.length() - 1);
        return query.toString();
    }

    private static class TrustAllCerts implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {
            // 不进行客户端证书验证
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {
            // 不进行服务器证书验证
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    private static class TrustAllHostnameVerifier implements HostnameVerifier {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

    private static SSLSocketFactory createSSLSocketFactory() {
        SSLSocketFactory ssfFactory = null;
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());
            ssfFactory = sc.getSocketFactory();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return ssfFactory;
    }

}
